﻿using System.Collections;
using Basic.HrService.Helper.Model;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
namespace Basic.HrService.Helper
{
    internal class PfxCertFileHelper
    {
        private static readonly string _SM2Algorithm = "1.2.156.10197.1.501";
        private static readonly string _RSAAlgorithm = "SHA256WITHRSA";
        public static byte[] CreateSM2Cert ( CertBody body )
        {
            X9ECParameters curve = ECNamedCurveTable.GetByName("sm2p256v1");
            SecureRandom random = new SecureRandom(new CryptoApiRandomGenerator());
            // 创建 SM2 密钥对生成器
            ECKeyPairGenerator generator = new ECKeyPairGenerator();
            generator.Init(new ECKeyGenerationParameters(new ECDomainParameters(curve), random));
            AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();
            return _CreateCert(random, keyPair, body, _SM2Algorithm);
        }
        public static CertInfo GetCertificateFromPfxFile ( Stream stream, string pwd )
        {
            Pkcs12StoreBuilder pfx = new Pkcs12StoreBuilder();
            Pkcs12Store store = pfx.Build();
            try
            {
                store.Load(stream, pwd.ToArray());
            }
            catch ( Exception )
            {
                return null;
            }
            IEnumerator e = store.Aliases.GetEnumerator();
            if ( !e.MoveNext() )
            {
                return null;
            }
            string name = e.Current.ToString();
            X509Certificate cert = store.GetCertificate(name).Certificate;
            return new CertInfo
            {
                CertName = name,
                BeginTime = cert.NotBefore.ToLocalTime(),
                EndTime = cert.NotAfter.ToLocalTime(),
                To = cert.SubjectDN.ToString().Split(',').Select(a => a.Split('=')).ToDictionary(a => a[0].Trim(), a => a[1].Trim()),
                Source = cert.IssuerDN.ToString().Split(',').Select(a => a.Split('=')).ToDictionary(a => a[0].Trim(), a => a[1].Trim())
            };
        }

        private static byte[] _CreateCert ( SecureRandom random, AsymmetricCipherKeyPair keyPair, CertBody body, string name )
        {
            ISignatureFactory signatureFactory = new Asn1SignatureFactory(name, keyPair.Private, random);

            //the certificate generator
            X509V3CertificateGenerator cert = new X509V3CertificateGenerator();

            SubjectPublicKeyInfo spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            //设置一些扩展字段
            //允许作为一个CA证书（可以颁发下级证书或进行签名）
            cert.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
            //使用者密钥标识符
            cert.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(spki));
            //授权密钥标识符
            cert.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(spki));

            //cert.AddExtension(X509Extensions.ExtendedKeyUsage.Id, true, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));

            //证书序列号
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
            cert.SetSerialNumber(serialNumber);

            cert.SetIssuerDN(new X509Name(new ArrayList
            {
                X509Name.C,
                X509Name.O,
                X509Name.OU,
                X509Name.CN,
                X509Name.E
            }, new Hashtable
            {
                [X509Name.C] = body.Source.Country ?? string.Empty,
                [X509Name.O] = body.Source.Company ?? string.Empty,
                [X509Name.OU] = body.Source.Dept ?? string.Empty,
                [X509Name.CN] = body.Source.SignName,
                [X509Name.E] = body.Source.Email ?? string.Empty,
            }));   //颁发者信息
            cert.SetSubjectDN(new X509Name(new ArrayList
            {
                X509Name.C,
                X509Name.O,
                X509Name.OU,
                X509Name.CN,
                X509Name.E
            }, new Hashtable
            {
                [X509Name.C] = body.To.Country ?? string.Empty,
                [X509Name.O] = body.To.Company ?? string.Empty,
                [X509Name.OU] = body.To.Dept ?? string.Empty,
                [X509Name.CN] = body.To.SignName,
                [X509Name.E] = body.To.Email ?? string.Empty,
            })); //使用者信息
            cert.SetNotBefore(body.BeginTime);   //证书生效时间
            cert.SetNotAfter(body.EndTime); //证书失效时间
            cert.SetPublicKey(keyPair.Public);

            X509Certificate certificate = cert.Generate(signatureFactory);
            X509CertificateEntry certEntry = new X509CertificateEntry(certificate);
            Pkcs12Store store = new Pkcs12StoreBuilder().Build();
            store.SetCertificateEntry(body.CertName, certEntry);   //设置证书  
            X509CertificateEntry[] chain = new X509CertificateEntry[1];
            chain[0] = certEntry;
            store.SetKeyEntry(body.CertName, new AsymmetricKeyEntry(keyPair.Private), chain);   //设置私钥  
            using ( MemoryStream fs = new MemoryStream() )
            {
                store.Save(fs, body.Pwd.ToCharArray(), random); //保存  
                return fs.ToArray();
            }
        }
        public static byte[] CreateRSACert ( CertBody body, int size )
        {
            SecureRandom random = new SecureRandom(new CryptoApiRandomGenerator());
            RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); //RSA密钥对生成器
            keyPairGenerator.Init(new KeyGenerationParameters(random, size));
            AsymmetricCipherKeyPair keyPair = keyPairGenerator.GenerateKeyPair();
            return _CreateCert(random, keyPair, body, _RSAAlgorithm);
        }
    }
}
